#include "hill_cipher.h"


Hill_Cipher::Hill_Cipher(int num)
{
    ROW = num;
    COL = num;
    for (int i = 0; i < ROW; i++)
        K.push_back(vector<int>(COL, 0));
    for (int j = 0; j < ROW; j++)
        D.push_back(vector<int>(COL, 0));
    for (int k = 0; k < ROW; k++)
        P.push_back(0);
    for (int m = 0; m < ROW; m++)
        F.push_back(0);
    for (int n = 0; n < ROW; n++)
        C.push_back(0);
    for (int i = 0; i < ROW; i++)
        cofa.push_back(vector<int>(COL, 0));
    for (int i = 0; i < ROW; i++)
        temp.push_back(vector<int>(COL, 0));
}


Hill_Cipher::~Hill_Cipher()
{}

std::string Hill_Cipher::KtoString()
{
    std::stringstream str1;
    char ch;
    for (int i = 0; i < ROW; i++)
        for (int j = 0; j < COL; j++)
        {
            ch = K[i][j] + 'A';
            str1 << ch;
        }
    std::string str2 = str1.str();
    return str2;
}

void Hill_Cipher::stringToK(std::string strKey)
{
    int x=0;
  const char* p = strKey.data();
  for(int i=0;i<ROW;i++)
      for(int j=0;j<COL;j++)
       {   K[i][j]=p[x]-'A';
            x++;
       }

}

void Hill_Cipher::stringToC(std::string strCiphertext)
{
    int x=0;
  const char* p = strCiphertext.data();
  for(int i=0;i<ROW;i++)
      {
        C[i]=p[x]-'A';
            x++;
      }
}

bool Hill_Cipher:: includeOtherChar(std::string inStr)
{
    char* str = (char*)inStr.data();
    char c;
    while(1)
    {
            c=*str++;
            if (c==0) break;  //如果到字符串尾则说明该字符串没有中文字符
            if (c<'a'||c>'z')       //如果字符高位为1且下一字符高位也是1则有中文字符
                     return 0;
        }
        return 1;
}

bool Hill_Cipher::includeOtherChar1(std::string inStr)
{

    char* str = (char*)inStr.data();
    char c;
    while(1)
    {
            c=*str++;
            if (c==0) break;  //如果到字符串尾则说明该字符串没有中文字符
            if (c<'A'||c>'Z')        //如果字符高位为1且下一字符高位也是1则有中文字符
                     return 0;
        }
        return 1;

}


//产生随机矩阵
void Hill_Cipher::creatRMatrix(int num)
{
    int i, j;
    for (i = 0; i <num ; i++)
    {
        for (j = 0; j < num; j++)
        {
            K[i][j] = rand() % 26;  //产生一个5*5模26的矩阵
        }
    }
}

//求矩阵的行列式
int Hill_Cipher::Det(vector<vector<int>> matrix, int row)
{
    int i, j;

    int m;   //l为所递归的余子阵的行
    int p = 0, q = 0;
    int sum = 0;
    if (row == 1)
        return matrix[0][0];
    for (i = 0; i < row; i++)
    {
        for (m = 0; m < row - 1; m++)
        {
            if (m < i)
                p = 0;
            else
                p = 1;
            for (j = 0; j < row - 1; j++)
            {
                cofa[m][j] = matrix[m + p][j + 1];
            }
        }
        //相当于(-1)^i
        if (i % 2 == 0)
            q = 1;
        else
            q = (-1);
        sum = sum + matrix[i][0] * q * Det(cofa, row - 1);
    }
    return sum;
}
int Hill_Cipher::gcd(int a, int b)
{
    int temp1;
    //交换两个数的大小,使得a为较大数
    if (a < b)
    {
        temp1 = a;
        a = b;
        b = temp1;
    }
    while (a % b)
    {
        temp1 = b;
        b = a % b;
        a = temp1;
    }
    return b;
}
bool Hill_Cipher::ifInverse(vector<vector<int>> matrix)
{
    if (gcd(Det(matrix, ROW), 26) == 1)
        return true;
    else
        return false;
}
void Hill_Cipher::multiphy(vector<vector<int>> matrix, vector<int>p, int row)
{
    int i, j;
    //先将密文单元清零
   // memset(C, 0, sizeof(C));
    for (int k = 0; k < ROW; k++)
            C[k] = 0;
    for (i = 0; i < ROW; i++)
    {
        for (j = 0; j < ROW; j++)
        {
            C[i] += P[j] * K[j][i];
        }
    }
}



//将明文加密为密文
std::string Hill_Cipher::encryption(std::string plaintext)
{
    int i;
    std::string ciphertext;
    //将字符串转化为明文数组
    for (i = 0; i < ROW; i++)
    {
        P[i] = plaintext[i] - 'a';
    }
    multiphy(K, P, ROW);
    //将密文数组转化为密文
    for (i = 0; i < ROW; i++)
        //这里先将其模26,再翻译为对应的字母
    {
        C[i] = Mod(C[i]);
       ciphertext += C[i] + 'A';
    }
    return ciphertext;
}
void Hill_Cipher::adjointMatrix(vector<vector<int>>matrix, int row)
{
    int i, j, k, l;
    int p, q;
    p = q = 0;
    for (i = 0; i < ROW; i++)
    {
        for (j = 0; j < ROW; j++)
        {
            for (k = 0; k < ROW - 1; k++)
            {
                if (k < i)
                    p = 0;
                else
                    p = 1;
                for (l = 0; l < ROW - 1; l++)
                {
                    if (l < j)
                        q = 0;
                    else
                        q = 1;
                    temp[k][l] = matrix[k + p][l + q];
                }
            }
            D[j][i] = (int)pow(-1, (double)i + j)*Det(temp, ROW - 1);
            D[j][i] = Mod(D[j][i]);
        }
    }
}
//将密文解密为明文(为了辨识清楚,我们统一以小写字母作为明文,大写字母作为密文)
std::string Hill_Cipher::deciphering()
{
    //求出矩阵的逆
    std::string text;
    int determinant = Det(K, ROW);
    int inver = inverse(determinant, 26);
    adjointMatrix(K, ROW);   //伴随矩阵
    int i, j;
    //memset(F, 0, sizeof(F));
    for (int k = 0; k < ROW; k++)
            F[k] = 0;
    for (i = 0; i < ROW; i++)
    {
        for (j = 0; j < ROW; j++)
        {
            F[i] += C[j] * D[j][i];
        }
        F[i] *= inver;
        F[i] = Mod(F[i]);   //算到的结果要模去26
    }
    for (i = 0; i < ROW; i++)
        text += F[i] + 'a';
    return text;
}

GCD Hill_Cipher::extendEuclid(int a, int b)
{
    GCD aa, bb;
    if (b == 0)
    {
        aa.x = 1;
        aa.y = 0;
        aa.d = a;
        return aa;
    }
    else
    {
        bb = extendEuclid(b, a%b);
        aa.x = bb.y;
        aa.y = bb.x - (a / b) * bb.y;
        aa.d = bb.d;
    }
    return aa;
}

int Hill_Cipher::inverse(int a, int m)
{
    GCD aa;
    aa = extendEuclid(a, m);
    return aa.x;
}
//返回传入的整数对26取模
int Hill_Cipher::Mod(int a)
{

    //原： return a >= 0 ? a % 26 : (26 + a % 26)
    //错误分析：当a<0且为26的整数倍（例：-26）则返回值为26+(-26)%26=26
    //明显不符合明文空间的要求(0~25)，会导致明文内容发生越界(发生在明文有“a”时)
        int b =a%26;
        return  b>=0 ? b : (26+b);
}


